#include<iostream>
#include<vector>
#include<string>
#include<unistd.h>
#include<cassert>
#include<cstdio>
#include<ctime>
#include<sys/types.h>
#include<sys/wait.h>

#define PROCESS_NUM 5
#define MakeSeed() srand((unsigned int)time(nullptr)^getpid()^rand())

using namespace std;

typedef void(*func)();

void task1()
{
    cout<<getpid()<<":下载"<<endl;
}

void task2()
{
    cout<<getpid()<<":IO"<<endl;
}

void task3()
{
    cout<<getpid()<<":刷新"<<endl;
}

void loadTaskFunc(vector<func>& f)
{
    f.push_back(task1);
    f.push_back(task2);
    f.push_back(task3);
}

class subEp
{
public:
    subEp(pid_t id,int writefd)
    :_id(id)
    ,_writefd(writefd)
    {
        char namebuf[1024];
        snprintf(namebuf,sizeof(namebuf),"process:%d[%d]-%d",num++,_id,_writefd);
        _name=namebuf;
    }
    static int num;
    pid_t _id;
    int _writefd;
    string _name;
};
int subEp::num=0;

void sendtask(subEp& subidx,int funcidx)
{
    cout<<"task:"<<funcidx<<"process name:"<<subidx._name<<endl;
    int n=write(subidx._writefd,&funcidx,sizeof(funcidx));
    assert(n==sizeof(int));
}

int recvtask(int fd)
{
    int code;
    ssize_t n=read(fd,&code,sizeof(code));
    if(n==4)
    {
        return code;
    }
    else
    {
        return -1;
    }
}

void creatProcess(vector<subEp>& subs,vector<func>& func_t)
{
    vector<int> deletefd;
    for(int i=0;i<PROCESS_NUM;++i)
    {
        int fds[2];
        int n=pipe(fds);
        assert(n==0);
        (void)n;
        pid_t id=fork();
        assert(id>=0);
        if(id==0)
        {
            //子进程  读
            for(int j=0;j<deletefd.size();++j) close(deletefd[j]);
            close(fds[1]);
            while(true)
            {
                int commandcode=recvtask(fds[0]);
                if(commandcode>=0&&commandcode<func_t.size())
                {
                    func_t[commandcode]();
                }
                else
                {
                    break;
                }
            }
            exit(0);
        }
        //父进程  写
        close(fds[0]);
        subEp s(id,fds[1]);
        subs.push_back(s);
        deletefd.push_back(fds[1]);
    }
}

void loadBlance(vector<subEp>& subs,vector<func>& func_t,int taskcnt)
{
    int subsize=subs.size();
    int funcsize=func_t.size();
    while(true)
    {
        if(taskcnt==0)
        {
            break;
        }
        int subidx=rand()%subsize;
        int funcidx=rand()%funcsize;
        sendtask(subs[subidx],funcidx);
        sleep(1);
        --taskcnt;
    }
    for(int i=0;i<subsize;++i)
    {
        close(subs[i]._writefd);
    }
}

void waitprocess(vector<subEp>& subs)
{
    for(int i=0;i<subs.size();++i)
    {
        waitpid(subs[i]._id,nullptr,0);
        cout<<"wait success:"<<subs[i]._id<<endl;
    }
}

int main()
{
    MakeSeed();

    vector<func> func_t;
    loadTaskFunc(func_t);

    vector<subEp> subs;
    creatProcess(subs,func_t);

    int taskcnt=10;
    loadBlance(subs,func_t,taskcnt);

    waitprocess(subs);

    return 0;
}